{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The String Widgets\n",
    "\n",
    "+ HTML\n",
    "+ HTMLMath\n",
    "+ Label\n",
    "+ Password\n",
    "+ Text\n",
    "+ TextArea"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These widgets are used to display data conventionally represented as strings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "{-# LANGUAGE OverloadedStrings #-}\n",
    "{-# LANGUAGE FlexibleContexts #-}\n",
    "import IHaskell.Display.Widgets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "-- Constructors\n",
    "html <- mkHTML\n",
    "htmlMath <- mkHTMLMath\n",
    "text <- mkText\n",
    "area <- mkTextArea\n",
    "pass <- mkPassword"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These widgets have a `Text` payload, represented by the `StringValue` field."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### HTML and Latex"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `HTML` widget displays `Text` as rich formatted *HTML*, but the `HTMLMath` widget can display *LaTeX* as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4077fda1-f1cf-4ebf-b560-24d3e031b89e",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "-- Display the widgets\n",
    "html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "-- Set some html string\n",
    "setField @StringValue html \"<b>Hello</b> <i>World!</i>\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2088fa59-fae3-4756-a7c2-d1ff2adfc298",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "-- Set some latex string\n",
    "setField @StringValue htmlMath \"$$\\\\sum_{i=0}^{i < n} i =\\\\frac{n\\\\cdot(n+1)}{2}$$\"\n",
    "htmlMath"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  `TextWidget`, `Password` & `TextArea`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These widgets allow you to obtain text input. First, let's see what they look like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1574dfdc-b482-4da1-8d54-4090a0c29632",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "97e3569f-0081-444c-86b6-9e65ab499163",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "498d1b85-fca3-48a3-84aa-17822e960bf6",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "text\n",
    "pass\n",
    "area"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first one has been created to input a word, but the second one is bigger and resizeable, making it better to big text input. The `TextWidget` and `TextArea` also have a `Placeholder` property, which represents the text displayed when the user has not made any input yet.\n",
    "\n",
    "> **NOTE ABOUT PASSWORD WIDGET**: This widget **is not** a **secure** way to collect sensitive information.\n",
    "> - The contents of the `Password` widget are transmitted unencrypted between the frontend and the kernel\n",
    "> - If you save the notebook, the contents of the widget are stored as plaintext"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "setField @Placeholder text \"Enter your text here...\"\n",
    "setField @Placeholder pass \"Password\"\n",
    "setField @Placeholder area \"Parsed output will appear here...\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "getField @StringValue text\n",
    "getField @StringValue pass\n",
    "getField @StringValue area"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The widgets also accept input. The `StringValue` of the widget is automatically updated on every change to the widget. Additionally, the `TextWidget` also has a `SubmitHandler` which is triggered on hitting the return/enter key."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below we set up the `TextWidget` and `TextArea` for parsing phone numbers using parsec. The `TextWidget` is used to recieve input, and the `TextArea` is used to display output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "-- Import parsec and other required libraries\n",
    "\n",
    "import Text.Parsec\n",
    "import Text.Parsec.String\n",
    "import Data.Text (pack, unpack)\n",
    "import Control.Applicative ((<$>))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we can write some parsers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "-- Parse a single digit\n",
    "digit :: Parser Char\n",
    "digit = oneOf ['0'..'9']\n",
    "\n",
    "-- Parse a multi-digit number.\n",
    "number :: Parser Integer\n",
    "number = do\n",
    "  digits <- many1 digit -- At least one digit\n",
    "  return (read digits)  -- Convert [Char] to Integer\n",
    "  \n",
    "-- Parse a country code, starting with a +.\n",
    "countryCode :: Parser Integer\n",
    "countryCode = do\n",
    "  char '+'\n",
    "  number\n",
    "  \n",
    "-- Parse an area code, optionally with parentheses.\n",
    "areaCode :: Parser Integer\n",
    "areaCode = choice [withParens, withoutParens]\n",
    "  where\n",
    "    withParens = between (char '(') (char ')') withoutParens\n",
    "    withoutParens = number\n",
    "  \n",
    "-- Simple data type representing a phone number.\n",
    "-- Real phone numbers are much more complex!\n",
    "data PhoneNumber = PhoneNumber {\n",
    "    phoneCountryCode :: Maybe Integer,\n",
    "    phoneNumbers :: [Integer]\n",
    "  } deriving (Eq, Show)\n",
    "  \n",
    "phoneNumber :: Parser PhoneNumber\n",
    "phoneNumber = do\n",
    "  -- Try to parse a country code. If it doesn't work, it's Nothing.\n",
    "  c <- optionMaybe countryCode\n",
    "  optional separator\n",
    "  a1 <- areaCode\n",
    "  separator -- Separator required after area code\n",
    "  a2 <- number\n",
    "  separator -- Separator required before last group of digits\n",
    "  a3 <- number\n",
    "  return (PhoneNumber c [a1, a2, a3])\n",
    "  \n",
    "  where\n",
    "    separator = oneOf \" -\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we set the `TextWidget`'s change handler to parse the input, and write the output to the `TextArea`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "setField @ChangeHandler text $ do\n",
    "  input <- unpack <$> getField @StringValue text\n",
    "  str <- case parse phoneNumber \"<text widget>\" input of\n",
    "             Left error -> return (show error)\n",
    "             Right x -> return (show x)\n",
    "  setField @StringValue area (pack str)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `TextArea` doesn't have a `SubmitHandler`, but does have a `ChangeHandler`. It is best used to display large amounts of text."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can re-display the widgets (nobody likes to scroll needlessly). Now you can input a telephone number on the text widget, and it should be parsed and displayed to the text area."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1574dfdc-b482-4da1-8d54-4090a0c29632",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "498d1b85-fca3-48a3-84aa-17822e960bf6",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "text\n",
    "area"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The `Password` widget\n",
    "\n",
    "It works the same as the `Text` widget, but it hides the text from the user. Can you guess the password and make the valid widget green?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "42d26919-28c0-41b5-9a69-2c37b7fd270c",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4e1bf52c-ad60-4280-bd94-2b38b953cf8a",
       "version_major": 2,
       "version_minor": 0
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "valid <- mkValid\n",
    "pwd <- mkPassword\n",
    "\n",
    "setField @ChangeHandler pwd $ getField @StringValue pwd >>= setField @BoolValue valid . (\"1234\"==)\n",
    "\n",
    "pwd\n",
    "valid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Haskell",
   "language": "haskell",
   "name": "haskell"
  },
  "language_info": {
   "codemirror_mode": "ihaskell",
   "file_extension": ".hs",
   "mimetype": "text/x-haskell",
   "name": "haskell",
   "pygments_lexer": "Haskell",
   "version": "9.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
